package io.summer.basis.api;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * @author ml
 */
@RestControllerAdvice
@Slf4j
public class AdviceApiResponse implements ResponseBodyAdvice<Object> {
  @Autowired
  private ObjectMapper objectMapper;

  @Override
  public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
    return AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), WrapResponse.class)
      || returnType.hasMethodAnnotation(WrapResponse.class);
  }

  @SneakyThrows
  @Override
  public Object beforeBodyWrite(@Nullable Object body, MethodParameter returnType, MediaType selectedContentType,
                                Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
                                ServerHttpResponse response) {
    if (body instanceof ApiResponse) {
      return body;
    }
    ApiResponse<?> apiResponse = ApiResponse.ok(body);
    if (body instanceof CharSequence) {
      //返回值为string, spring 会使用StringHttpMessageConverter，不会接受ApiResponse类型
      //here use StringHttpMessageConverter, convert result to string and return it.
      //StringHttpMessageConverter process all type of content-type
      return objectMapper.writeValueAsString(apiResponse);
    }
    return apiResponse;
  }
}
